﻿using System;
using System.Collections.Generic;

namespace NetTopologySuite.Index.IntervalRTree
{
	public class SortedPackedIntervalRTree<T>
	{
		public void Insert(double min, double max, T item)
		{
			if (this._root != null)
			{
				throw new InvalidOperationException("Index cannot be added to once it has been queried");
			}
			this._leaves.Add(new IntervalRTreeLeafNode<T>(min, max, item));
		}

		private void Init()
		{
			if (this._root != null)
			{
				return;
			}
			object leavesLock = this._leavesLock;
			lock (leavesLock)
			{
				if (this._root == null)
				{
					this._root = this.BuildTree();
				}
			}
		}

		private IntervalRTreeNode<T> BuildTree()
		{
			this._leaves.Sort(IntervalRTreeNode<T>.NodeComparator.Instance);
			List<IntervalRTreeNode<T>> list = this._leaves;
			List<IntervalRTreeNode<T>> list2 = new List<IntervalRTreeNode<T>>();
			int num = 0;
			for (;;)
			{
				SortedPackedIntervalRTree<T>.BuildLevel(list, list2, ref num);
				if (list2.Count == 1)
				{
					break;
				}
				List<IntervalRTreeNode<T>> list3 = list;
				list = list2;
				list2 = list3;
			}
			return list2[0];
		}

		private static void BuildLevel(List<IntervalRTreeNode<T>> src, List<IntervalRTreeNode<T>> dest, ref int level)
		{
			level++;
			dest.Clear();
			for (int i = 0; i < src.Count; i += 2)
			{
				IntervalRTreeNode<T> item = src[i];
				if (((i + 1 < src.Count) ? src[i] : null) == null)
				{
					dest.Add(item);
				}
				else
				{
					IntervalRTreeBranchNode<T> item2 = new IntervalRTreeBranchNode<T>(src[i], src[i + 1]);
					dest.Add(item2);
				}
			}
		}

		public void Query(double min, double max, IItemVisitor<T> visitor)
		{
			this.Init();
			this._root.Query(min, max, visitor);
		}

		private readonly object _leavesLock = new object();

		private readonly List<IntervalRTreeNode<T>> _leaves = new List<IntervalRTreeNode<T>>();

		private volatile IntervalRTreeNode<T> _root;
	}
}
